package com.tengju.bff.application.wx;

import com.tengju.bff.application.shared.ApplicationException;
import com.tengju.bff.domain.service.WxLockService;
import com.tengju.data.domain.model.clickhouse.DwsUserDominationTeamParent;
import com.tengju.data.domain.model.user.DominationDetailRepository;
import com.tengju.data.domain.model.user.StarLevelEnum;
import com.tengju.data.domain.model.user.UserIdCode;
import com.tengju.data.domain.model.wx.WxRequestRecordFactory;
import com.tengju.data.domain.model.wx.WxRequestRecordRepository;
import com.tengju.data.domain.model.wx.WxUserInfo;
import com.tengju.data.domain.model.wx.WxUserInfoRepository;
import com.tengju.data.domain.shared.IdObject;
import com.tengju.data.domain.shared.JsonUtil;
import com.tengju.data.domain.shared.tree.Forest;
import com.tengju.data.domain.shared.tree.StableTree;
import com.tengju.data.domain.shared.tree.Tree;
import com.tengju.data.domain.shared.tree.TreeNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.tengju.bff.application.shared.ApplicationExceptionCode.WORK_WEIXIN_LOCK_ERROR;
import static com.tengju.data.domain.model.wx.WxRequestRecordType.*;

/**
 * @author: 李大仙
 * @date: 2021/11/5 11:04 上午
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class WxUserDepartmentManageJobService {

    private final DominationDetailRepository dominationDetailRepository;
    private final WxUserInfoRepository wxUserInfoRepository;
    private final WxRequestRecordRepository wxRequestRecordRepository;
    private final WxLockService wxLockService;

    @Value("${weixin.work.user.department.filter.idcode}")
    private String weixinFilterIdCodeStr;
    @Value("${weixin.work.user.idcode.blacklist}")
    private String weixinUserIdCodeBlacklistStr;
    @Value("${weixin.work.user.remove.root.idcode}")
    private String weixinUserRemoveRootIdCodeStr;

    public static final Long wxMaxId = 4294967295L;

    public void execute() {
        String key = "WX_USER_DEPARTMENT_MANAGE_JOB_" + LocalDate.now().toString();
        RLock lock = wxLockService.getLock(key);
        if (lock.tryLock()) {
            try {
                // 旧的部门树
                Forest<WxUserInfo> oldDeptForest = new Forest<>();
                // 新的部门树
                Forest<WxUserInfo> newDeptForest = new Forest<>();
                // 新的用户树
                Forest<WxUserInfo> newUserForest = new Forest<>();

                // 获取所有历史数据
                List<WxUserInfo> oldWxUserInfoList = wxUserInfoRepository.selectAll();
                buildDeptTree(oldWxUserInfoList, oldDeptForest);
                log.info("oldWxUserInfoList userSize: {}, deptSize: {}",
                        oldWxUserInfoList.size(), oldDeptForest.countNodes());

                List<WxUserInfo> newWxUserInfoList;
                List<Long> weixinFilterIdCodeList = getFilterIdCodeList();
                if (CollectionUtils.isEmpty(weixinFilterIdCodeList)) {
                    newWxUserInfoList = getNewWxUserInfoList();
                } else {
                    newWxUserInfoList = getNewWxUserInfoList(weixinFilterIdCodeList);
                }
                buildDeptTree(newWxUserInfoList, newDeptForest);
                log.info("newWxUserInfoList size: {}, deptSize: {}",
                        newWxUserInfoList.size(), newDeptForest.countNodes());
                buildUserTree(newWxUserInfoList, newUserForest);

                List<Long> weixinUserIdCodeBlacklist = getUserIdCodeBlacklist();

                // 处理部门树
                processDept(oldDeptForest, newDeptForest, newUserForest, weixinUserIdCodeBlacklist);
                // 获取需要移除的根节点下的所有节点
                List<Long> removeRootUserInfoIdCodeList = getRemoveRootUserInfoIdCodeList(newUserForest);
                // 处理用户
                processUser(oldWxUserInfoList, newWxUserInfoList, newUserForest, removeRootUserInfoIdCodeList, weixinUserIdCodeBlacklist);
            } finally {
                lock.unlock();
            }
        } else {
            throw ApplicationException.error(WORK_WEIXIN_LOCK_ERROR, key);
        }
    }

    List<Long> getRemoveRootUserInfoIdCodeList(Forest<WxUserInfo> forest) {
        List<Long> result = new ArrayList<>();
        List<Long> removeRootIdCodeList = getRemoveRootIdCodeList();
        for (StableTree<WxUserInfo> stableTree : forest.getStableTrees()) {
            if (removeRootIdCodeList.contains(stableTree.getRoot().getData().getIdCode().getValue())) {
                result.addAll(stableTree.getAllNodes().stream()
                        .map(t -> t.getData().getIdCode().getValue())
                        .collect(Collectors.toList()));
            }
        }
        return result;
    }

    private void processUser(List<WxUserInfo> oldWxUserInfoList,
                             List<WxUserInfo> newWxUserInfoList,
                             Forest<WxUserInfo> newUserForest,
                             List<Long> removeRootUserInfoIdCodeList,
                             List<Long> weixinUserIdCodeBlacklist) {
        Map<UserIdCode, WxUserInfo> oldWxUserInfoMap = oldWxUserInfoList.stream()
                .collect(Collectors.toMap(WxUserInfo::getIdCode, v -> v, (m1, m2) -> m1));
        for (WxUserInfo newWxUserInfo : newWxUserInfoList) {
            UserIdCode newUserIdCode = newWxUserInfo.getIdCode();
            // 过滤掉黑名单用户
            if (weixinUserIdCodeBlacklist.contains(newUserIdCode.getValue())) {
                continue;
            }
            // 过滤掉需要移除的根节点下的所有节点
            if (removeRootUserInfoIdCodeList.contains(newUserIdCode.getValue())) {
                continue;
            }
            WxUserInfo oldWxUserInfo = oldWxUserInfoMap.get(newUserIdCode);
            if (oldWxUserInfo != null) {
                // 老树中有
                Long oldUserDepartmentId = oldWxUserInfo.getDepartmentId();
                Long newUserDepartmentId = newWxUserInfo.getDepartmentId();
                newWxUserInfo.setTagIdList(oldWxUserInfo.getTagIdList());
                newWxUserInfo.setWxActivateStatus(oldWxUserInfo.getWxActivateStatus());
                if (!oldUserDepartmentId.equals(newUserDepartmentId)) {
                    // 更新
                    wxRequestRecordRepository.batchInsert(
                            List.of(WxRequestRecordFactory.create(
                                    UPDATE_USER_DEPARTMENT,
                                    JsonUtil.toJSONString(oldWxUserInfo),
                                    JsonUtil.toJSONString(newWxUserInfo)))
                    );
                } else {
                    StarLevelEnum oldStarLevel = oldWxUserInfo.getStarLevel();
                    StarLevelEnum newStarLevel = newWxUserInfo.getStarLevel();
                    if (oldStarLevel != newStarLevel) {
                        wxUserInfoRepository.insertOrUpdate(newWxUserInfo);
                    }
                }

                // 处理历史上级删除
                processHistoryDominationDelete(newWxUserInfo, newUserForest, oldWxUserInfo);

                // 处理历史上级新增
                processHistoryDominationAdd(newWxUserInfo, newUserForest, oldWxUserInfo);

                oldWxUserInfoMap.remove(newUserIdCode);
            } else {
                // 新增用户
                wxRequestRecordRepository.batchInsert(
                        List.of(WxRequestRecordFactory.createAfter(
                                CREATE_USER_DEPARTMENT,
                                JsonUtil.toJSONString(newWxUserInfo)))
                );
            }
        }

        for (Map.Entry<UserIdCode, WxUserInfo> entry : oldWxUserInfoMap.entrySet()) {
            WxUserInfo wxUserInfo = entry.getValue();
            wxRequestRecordRepository.batchInsert(
                    List.of(WxRequestRecordFactory.createBefore(
                            DELETE_USER_DEPARTMENT,
                            JsonUtil.toJSONString(wxUserInfo)))
            );
        }
    }

    private void processDept(Forest<WxUserInfo> oldDeptForest,
                             Forest<WxUserInfo> newDeptForest,
                             Forest<WxUserInfo> newUserForest,
                             List<Long> weixinUserIdCodeBlacklist) {

        Map<Integer, Set<TreeNode<WxUserInfo>>> oldDeptDepthDictionary = new HashMap<>();
        Map<Integer, Set<TreeNode<WxUserInfo>>> newDeptDepthDictionary = new HashMap<>();

        buildDepthDictionary(oldDeptDepthDictionary, oldDeptForest);
        buildDepthDictionary(newDeptDepthDictionary, newDeptForest);

        int maxDeptDepth = getMaxDepth(oldDeptDepthDictionary, newDeptDepthDictionary);

        // 获取降级或需要删除的部门
        Map<UserIdCode, WxUserInfo> deleteDeptMap = getDeleteDeptMap(oldDeptDepthDictionary, newDeptDepthDictionary, weixinUserIdCodeBlacklist);

        for (int depth = 0; depth <= maxDeptDepth; depth++) {
            Map<UserIdCode, WxUserInfo> oldDeptCurrentDepthMap = getCurrentDepthMap(oldDeptDepthDictionary, depth);
            Map<UserIdCode, WxUserInfo> newDeptCurrentDepthMap = getCurrentDepthMap(newDeptDepthDictionary, depth);

            // 新树为基准
            for (Map.Entry<UserIdCode, WxUserInfo> entry : newDeptCurrentDepthMap.entrySet()) {
                // 过滤掉黑名单用户
                if (weixinUserIdCodeBlacklist.contains(entry.getKey().getValue())) {
                    continue;
                }
                WxUserInfo newWxUserInfo = entry.getValue();
                if (oldDeptCurrentDepthMap.containsKey(newWxUserInfo.getIdCode())) {
                    // 在同一层中，新树、老树都有
                    WxUserInfo oldWxUserInfo = oldDeptCurrentDepthMap.get(newWxUserInfo.getIdCode());

                    newWxUserInfo.setTagIdList(oldWxUserInfo.getTagIdList());
                    newWxUserInfo.setWxActivateStatus(oldWxUserInfo.getWxActivateStatus());

                    processDominationIdCode(newWxUserInfo, newUserForest, oldWxUserInfo);

                } else {
                    // 在同一层中，新树有，老树没有，说明数据发生升级
                    WxUserInfo oldWxUserInfo = deleteDeptMap.get(newWxUserInfo.getIdCode());
                    if (oldWxUserInfo != null) {
                        // 老树中以前有
                        newWxUserInfo.setTagIdList(oldWxUserInfo.getTagIdList());
                        newWxUserInfo.setWxActivateStatus(oldWxUserInfo.getWxActivateStatus());

                        processDominationIdCode(newWxUserInfo, newUserForest, oldWxUserInfo);

                        // 从待删除部门列表移除
                        deleteDeptMap.remove(newWxUserInfo.getIdCode());
                    } else {
                        // 说明是新部门
                        wxRequestRecordRepository.batchInsert(
                                List.of(WxRequestRecordFactory.createAfter(
                                        CREATE_DEPARTMENT,
                                        JsonUtil.toJSONString(newWxUserInfo)))
                        );
                        // 把上级新增到当前部门
                        wxRequestRecordRepository.batchInsert(
                                List.of(WxRequestRecordFactory.createAfter(
                                        ADD_INTO_CURRENT_DEPARTMENT,
                                        JsonUtil.toJSONString(newWxUserInfo)))
                        );
                        wxRequestRecordRepository.batchInsert(
                                List.of(WxRequestRecordFactory.createAfter(
                                        CREATE_DEALER_DEPARTMENT,
                                        JsonUtil.toJSONString(newWxUserInfo)))
                        );
                        // 把自己新增到当前子部门
                        wxRequestRecordRepository.batchInsert(
                                List.of(WxRequestRecordFactory.createAfter(
                                        ADD_INTO_DEALER_DEPARTMENT,
                                        JsonUtil.toJSONString(newWxUserInfo)))
                        );
                        // 给部门打上「限制访问外部门」的标签
                        wxRequestRecordRepository.batchInsert(
                                List.of(WxRequestRecordFactory.createAfter(
                                        CREATE_DEPARTMENT_LIMIT_ACCESS_TO_OUTSIDE_DEPARTMENTS_TAG,
                                        JsonUtil.toJSONString(newWxUserInfo)))
                        );
                    }
                }
            }
        }

        for (Map.Entry<UserIdCode, WxUserInfo> entry : deleteDeptMap.entrySet()) {
            WxUserInfo wxUserInfo = entry.getValue();
            // 把老的上级移出当前部门
            wxRequestRecordRepository.batchInsert(
                    List.of(WxRequestRecordFactory.createAfter(
                            MOVE_OUT_CURRENT_DEPARTMENT,
                            JsonUtil.toJSONString(wxUserInfo)))
            );
            wxRequestRecordRepository.batchInsert(
                    List.of(WxRequestRecordFactory.createBefore(
                            DELETE_DEPARTMENT,
                            JsonUtil.toJSONString(wxUserInfo)))
            );
            wxRequestRecordRepository.batchInsert(
                    List.of(WxRequestRecordFactory.createAfter(
                            MOVE_OUT_DEALER_DEPARTMENT,
                            JsonUtil.toJSONString(wxUserInfo)))
            );
        }
    }

    private void processHistoryDominationAdd(WxUserInfo newWxUserInfo, Forest<WxUserInfo> newDeptForest,
                                             WxUserInfo oldWxUserInfo) {
        StarLevelEnum newWxUserInfoStarLevel = newWxUserInfo.getStarLevel();
        Integer newWxUserInfoStarLevelCode = newWxUserInfoStarLevel.getCode();

        if (oldWxUserInfo.getDominationIdCode() != null) {
            TreeNode<WxUserInfo> newTreeOldDominationTreeNode = newDeptForest.findNode(oldWxUserInfo.getDominationIdCode());
            if (newTreeOldDominationTreeNode != null) {
                WxUserInfo newTreeOldDominationUserInfo = newTreeOldDominationTreeNode.getData();
                Integer newTreeOldDominationUserInfoStarLevelCode = newTreeOldDominationUserInfo.getStarLevel().getCode();
                if (newTreeOldDominationUserInfoStarLevelCode.equals(newWxUserInfoStarLevelCode)
                        && StarLevelEnum.NONE != newWxUserInfoStarLevel) {
                    // 跟上一次上级等级相等
                    newWxUserInfo.setHistoryDominationIdCode(newTreeOldDominationUserInfo.getIdCode());
                    wxRequestRecordRepository.batchInsert(
                            List.of(WxRequestRecordFactory.create(
                                    HISTORY_ADD_INTO_CURRENT_DEPARTMENT,
                                    JsonUtil.toJSONString(newTreeOldDominationUserInfo),
                                    JsonUtil.toJSONString(newWxUserInfo)))
                    );
                }
            }
        }
    }

    private void processHistoryDominationDelete(WxUserInfo newWxUserInfo, Forest<WxUserInfo> newUserForest,
                                                WxUserInfo oldWxUserInfo) {
        StarLevelEnum newWxUserInfoStarLevel = newWxUserInfo.getStarLevel();
        StarLevelEnum oldWxUserInfoStarLevel = oldWxUserInfo.getStarLevel();
        Integer newWxUserInfoStarLevelCode = newWxUserInfoStarLevel.getCode();
        Integer oldWxUserInfoStarLevelCode = oldWxUserInfoStarLevel.getCode();
        if (newWxUserInfoStarLevelCode.equals(oldWxUserInfoStarLevelCode)) {
            return;
        }
        if (oldWxUserInfo.getHistoryDominationIdCode() != null) {
            TreeNode<WxUserInfo> newTreeOldHistoryDominationTreeNode = newUserForest.findNode(oldWxUserInfo.getHistoryDominationIdCode());
            if (newTreeOldHistoryDominationTreeNode != null) {
                WxUserInfo newTreeOldHistoryDominationUserInfo = newTreeOldHistoryDominationTreeNode.getData();
                Integer newTreeOldHistoryDominationUserInfoStarLevelCode = newTreeOldHistoryDominationUserInfo.getStarLevel().getCode();

                // 当前等级大于历史上级，断开
                if (newWxUserInfoStarLevelCode > newTreeOldHistoryDominationUserInfoStarLevelCode) {
                    newWxUserInfo.setHistoryDominationIdCode(null);
                    wxRequestRecordRepository.batchInsert(
                            List.of(WxRequestRecordFactory.create(
                                    HISTORY_MOVE_OUT_CURRENT_DEPARTMENT,
                                    JsonUtil.toJSONString(newTreeOldHistoryDominationUserInfo),
                                    JsonUtil.toJSONString(newWxUserInfo)))
                    );
                }

                if (newWxUserInfoStarLevelCode.equals(newTreeOldHistoryDominationUserInfoStarLevelCode)
                        && StarLevelEnum.NONE == newWxUserInfoStarLevel) {
                    newWxUserInfo.setHistoryDominationIdCode(null);
                    wxRequestRecordRepository.batchInsert(
                            List.of(WxRequestRecordFactory.create(
                                    HISTORY_MOVE_OUT_CURRENT_DEPARTMENT,
                                    JsonUtil.toJSONString(newTreeOldHistoryDominationUserInfo),
                                    JsonUtil.toJSONString(newWxUserInfo)))
                    );
                }
            }
        }
    }

    private void processDominationIdCode(WxUserInfo newWxUserInfo,
                                         Forest<WxUserInfo> newUserForest,
                                         WxUserInfo oldWxUserInfo) {
        Long oldDominationIdCodeVal = Optional.ofNullable(oldWxUserInfo.getDominationIdCode()).map(IdObject::getValue).orElse(0L);
        Long oldHistoryDominationIdCodeVal = Optional.ofNullable(oldWxUserInfo.getHistoryDominationIdCode()).map(IdObject::getValue).orElse(0L);
        Long newDominationIdCodeVal = Optional.ofNullable(newWxUserInfo.getDominationIdCode()).map(IdObject::getValue).orElse(0L);

        if (!oldDominationIdCodeVal.equals(newDominationIdCodeVal)) {
            // 部门的pid需要变更
            wxRequestRecordRepository.batchInsert(
                    List.of(WxRequestRecordFactory.createAfter(
                            UPDATE_DEPARTMENT,
                            JsonUtil.toJSONString(newWxUserInfo)))
            );
            boolean flag = true;
            if (!oldHistoryDominationIdCodeVal.equals(0L)){
                TreeNode<WxUserInfo> oldHistoryDomination = newUserForest.findNode(new UserIdCode(oldHistoryDominationIdCodeVal));
                if (oldHistoryDomination != null
                        && oldHistoryDomination.getData().getStarLevel() == newWxUserInfo.getStarLevel()
                        && oldDominationIdCodeVal.equals(oldHistoryDominationIdCodeVal)){
                    flag = false;
                }
            }

            if (flag){
                // 把老的上级移出当前部门
                wxRequestRecordRepository.batchInsert(
                        List.of(WxRequestRecordFactory.createAfter(
                                MOVE_OUT_CURRENT_DEPARTMENT,
                                JsonUtil.toJSONString(oldWxUserInfo)))
                );
            }

            // 把上级新增到当前部门
            wxRequestRecordRepository.batchInsert(
                    List.of(WxRequestRecordFactory.createAfter(
                            ADD_INTO_CURRENT_DEPARTMENT,
                            JsonUtil.toJSONString(newWxUserInfo)))
            );
        }
    }

    private Map<UserIdCode, WxUserInfo> getDeleteDeptMap(Map<Integer, Set<TreeNode<WxUserInfo>>> oldDeptDepthDictionary, Map<Integer, Set<TreeNode<WxUserInfo>>> newDeptDepthDictionary, List<Long> weixinUserIdCodeBlacklist) {
        Map<UserIdCode, WxUserInfo> deleteDeptMap = new HashMap<>();

        int maxDeptDepth = getMaxDepth(oldDeptDepthDictionary, newDeptDepthDictionary);

        for (int depth = 0; depth <= maxDeptDepth; depth++) {
            Map<UserIdCode, WxUserInfo> oldDeptDepthMap = getCurrentDepthMap(oldDeptDepthDictionary, depth);
            Map<UserIdCode, WxUserInfo> newDeptDepthMap = getCurrentDepthMap(newDeptDepthDictionary, depth);

            // 老树为基准
            for (Map.Entry<UserIdCode, WxUserInfo> entry : oldDeptDepthMap.entrySet()) {
                // 过滤掉黑名单用户
                if (weixinUserIdCodeBlacklist.contains(entry.getKey().getValue())) {
                    continue;
                }
                WxUserInfo oldWxUserInfo = entry.getValue();
                if (!newDeptDepthMap.containsKey(oldWxUserInfo.getIdCode())) {
                    // 在同一层中，新树中没有，老树中有
                    // 标记为需要删除的部门
                    deleteDeptMap.put(oldWxUserInfo.getIdCode(), oldWxUserInfo);
                }
            }
        }
        return deleteDeptMap;
    }

    private Map<UserIdCode, WxUserInfo> getCurrentDepthMap(Map<Integer, Set<TreeNode<WxUserInfo>>> deptDepthDictionary, int depth) {
        Set<TreeNode<WxUserInfo>> treeNodeSet = deptDepthDictionary.get(depth);
        Map<UserIdCode, WxUserInfo> result = new HashMap<>();
        if (!CollectionUtils.isEmpty(treeNodeSet)) {
            result = treeNodeSet.stream()
                    .collect(Collectors.toMap(k -> k.getData().getIdCode(), TreeNode::getData, (m1, m2) -> m1));
        }
        return result;
    }

    public List<Long> getUserIdCodeBlacklist() {
        List<Long> weixinUserIdCodeBlacklist = new ArrayList<>();
        if (!StringUtils.isEmpty(weixinUserIdCodeBlacklistStr)) {
            weixinUserIdCodeBlacklist = Arrays.stream(weixinUserIdCodeBlacklistStr.split(","))
                    .map(Long::parseLong)
                    .collect(Collectors.toList());
        }
        return weixinUserIdCodeBlacklist;
    }

    public List<Long> getRemoveRootIdCodeList() {
        List<Long> weixinRemoveRootIdCodelist = new ArrayList<>();
        if (!StringUtils.isEmpty(weixinUserRemoveRootIdCodeStr)) {
            weixinRemoveRootIdCodelist = Arrays.stream(weixinUserRemoveRootIdCodeStr.split(","))
                    .map(Long::parseLong)
                    .collect(Collectors.toList());
        }
        return weixinRemoveRootIdCodelist;
    }

    public List<Long> getFilterIdCodeList() {
        List<Long> weixinFilterIdCodeList = new ArrayList<>();
        if (!StringUtils.isEmpty(weixinFilterIdCodeStr)) {
            weixinFilterIdCodeList = Arrays.stream(weixinFilterIdCodeStr.split(","))
                    .map(Long::parseLong)
                    .collect(Collectors.toList());
        }
        return weixinFilterIdCodeList;
    }

    private List<WxUserInfo> getNewWxUserInfoList(List<Long> weixinFilterIdCodeList) {
        List<UserIdCode> dominationIdCodeList = weixinFilterIdCodeList.stream()
                .map(UserIdCode::new)
                .collect(Collectors.toList());
        // 获取所有管辖团队根节点
        List<DwsUserDominationTeamParent> eecDominationTeamParent = dominationDetailRepository.getEecDominationTeamParentByDominationIdCodeList(dominationIdCodeList);
        // 获取所有管辖团队除根节点外的所有节点
        List<DwsUserDominationTeamParent> userDominationTeamParent = dominationDetailRepository.getUserDominationTeamParentByDominationIdCodeList(dominationIdCodeList);

        return buildWxUserInfoList(eecDominationTeamParent, userDominationTeamParent);
    }

    private List<WxUserInfo> getNewWxUserInfoList() {
        // 获取所有管辖团队根节点
        List<DwsUserDominationTeamParent> eecDominationTeamParent = dominationDetailRepository.getEecDominationTeamParent();
        // 获取所有管辖团队除根节点外的所有节点
        List<DwsUserDominationTeamParent> userDominationTeamParent = dominationDetailRepository.getUserDominationTeamParent();

        return buildWxUserInfoList(eecDominationTeamParent, userDominationTeamParent);
    }

    private List<WxUserInfo> buildWxUserInfoList(List<DwsUserDominationTeamParent> eecDominationTeamParent, List<DwsUserDominationTeamParent> userDominationTeamParent) {
        List<WxUserInfo> wxEecUserInfoList = eecDominationTeamParent.stream()
                .map(s -> new WxUserInfo(s.getIdCode(),
                        s.getIdCode().getValue(),
                        s.getDominationIdCode(),
                        null,
                        null,
                        s.getStarLevel(),
                        new ArrayList<>()))
                .collect(Collectors.toList());

        List<WxUserInfo> wxUserInfoList = userDominationTeamParent.stream()
                .map(s -> {
                    long departmentId = s.getStarLevel().isServiceStarLevel() ?
                            s.getIdCode().getValue() : wxMaxId - s.getDominationIdCode().getValue();
                    return new WxUserInfo(s.getIdCode(),
                            departmentId,
                            s.getDominationIdCode(),
                            null,
                            null,
                            s.getStarLevel(),
                            new ArrayList<>());
                })
                .collect(Collectors.toList());
        wxEecUserInfoList.addAll(wxUserInfoList);
        return wxEecUserInfoList;
    }

    private void buildDepthDictionary(Map<Integer, Set<TreeNode<WxUserInfo>>> currentDepthDictionary,
                                      Forest<WxUserInfo> oldUserForest) {
        List<Long> removeRootIdCodeList = getRemoveRootIdCodeList();
        for (StableTree<WxUserInfo> stableTree : oldUserForest.getStableTrees()) {
            log.info("stableTree: {}", JsonUtil.toJSONString(stableTree.getRoot().getData()));
            if (!removeRootIdCodeList.contains(stableTree.getRoot().getData().getIdCode().getValue())) {
                for (Map.Entry<Integer, Set<TreeNode<WxUserInfo>>> entry : stableTree.getDepthDictionary().entrySet()) {
                    Integer key = entry.getKey();
                    Set<TreeNode<WxUserInfo>> value = entry.getValue();
                    Set<TreeNode<WxUserInfo>> treeNodeSet = currentDepthDictionary.get(key);
                    if (CollectionUtils.isEmpty(treeNodeSet)) {
                        currentDepthDictionary.put(key, value);
                    } else {
                        treeNodeSet.addAll(value);
                    }
                }
            }
        }
    }

    private int getMaxDepth(Map<Integer, Set<TreeNode<WxUserInfo>>> oldDepthDictionary,
                            Map<Integer, Set<TreeNode<WxUserInfo>>> newDepthDictionary) {
        Set<Integer> oldDepthSet = oldDepthDictionary.keySet();
        int oldDepth = oldDepthSet.stream().max(Integer::compare).orElse(0);

        Set<Integer> newDepthSet = newDepthDictionary.keySet();
        int newDepth = newDepthSet.stream().max(Integer::compare).orElse(0);

        return Math.max(oldDepth, newDepth);
    }

    /**
     * 生成部门树
     */
    public void buildDeptTree(List<WxUserInfo> wxUserInfoList, Forest<WxUserInfo> forest) {
        List<Future<Tree<WxUserInfo>>> taskList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(wxUserInfoList)) {
            for (WxUserInfo wxUserInfo : wxUserInfoList) {
                if (wxUserInfo.getStarLevel() != StarLevelEnum.NONE) {
                    Future<Tree<WxUserInfo>> deptTask = forest.asyncPutNode(wxUserInfo, wxUserInfo.getDominationIdCode());
                    taskList.add(deptTask);
                }
            }
        }
        taskList.forEach(t -> {
            try {
                t.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        });
        forest.finishSetUp();
    }

    /**
     * 生成用户树
     */
    public void buildUserTree(List<WxUserInfo> wxUserInfoList, Forest<WxUserInfo> forest) {
        List<Future<Tree<WxUserInfo>>> taskList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(wxUserInfoList)) {
            for (WxUserInfo wxUserInfo : wxUserInfoList) {
                Future<Tree<WxUserInfo>> deptTask = forest.asyncPutNode(wxUserInfo, wxUserInfo.getDominationIdCode());
                taskList.add(deptTask);
            }
        }
        taskList.forEach(t -> {
            try {
                t.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        });
        forest.finishSetUp();
    }
}
